#include "models.hpp"

#include "spdlog/spdlog.h"

#include <assert.h>

#include "../select/select.hpp"
#include "events.hpp"

namespace qbe::state {

bool State::adsorption = false;
bool State::angleTheAdsorption = false;
bool State::angleLocking = false;

std::map<DrawingModeType, std::string> drawModeToStrMap = {
    {DrawingModeType::None, "None"},   {DrawingModeType::Circle, "Circle"},     {DrawingModeType::Ellipse, "Ellipse"},
    {DrawingModeType::Fan, "Fan"},     {DrawingModeType::KeyPoint, "KeyPoint"}, {DrawingModeType::Label, "Label"},
    {DrawingModeType::Path, "Path"},   {DrawingModeType::Polygon, "Polygon"},   {DrawingModeType::Rectangle, "Rectangle"},
    {DrawingModeType::Ruler, "Ruler"}, {DrawingModeType::Text, "Text"},
};

std::map<SelectModeType, std::string> selectModeToStrMap = {{SelectModeType::None, "None"},
                                                            {SelectModeType::Overall, "Overall"},
                                                            {SelectModeType::Part, "Part"}};

std::map<EditingModeType, std::string> editingModeToStrMap = {{EditingModeType::None, "None"},
                                                              {EditingModeType::Move, "Move"},
                                                              {EditingModeType::Copy, "Copy"},
                                                              {EditingModeType::Affix, "Affix"}};

std::string mode_to_string(AllModeType type) {
  return {};
  if (isModeType<DrawingModeType>(type)) {
    return drawModeToStrMap[getModeType<DrawingModeType>(type)];
  }
  if (isModeType<EditingModeType>(type)) {
    return editingModeToStrMap[getModeType<EditingModeType>(type)];
  }
  if (isModeType<SelectModeType>(type)) {
    return selectModeToStrMap[getModeType<SelectModeType>(type)];
  }
}

std::string getModeInfo(State& state) {
  return ("DrawingMode: " + mode_to_string(state.getDrawingMode())) + " EditingMode: " + mode_to_string(state.getEditingMode()) +
         " SelectMode: " + mode_to_string(state.getSelectMode());
}

State::State(ecs::Query _query, ecs::Bus& _bus) : query(_query), bus(_bus) {
  drawingMode = DrawingModeType::None;
  editingMode = EditingModeType::None;
  selectMode = SelectModeType::Overall;

  exitSelectMode = SelectModeType::Overall;
}

DrawingModeType State::getDrawingMode() const {
  return drawingMode;
}
EditingModeType State::getEditingMode() const {
  return editingMode;
}
SelectModeType State::getSelectMode() const {
  return selectMode;
}

void State::addExitCall(DrawingModeType mode, const ExitCallback& ecb) {
  exitManager.add(mode, ecb);
}
void State::addExitCall(EditingModeType mode, const ExitCallback& ecb) {
  exitManager.add(mode, ecb);
}
void State::addExitCall(SelectModeType mode, const ExitCallback& ecb) {
  exitManager.add(mode, ecb);
}

void State::cjExitCall(const ExitCallback& ecb) {
  exitManager.cj_exitCall = ecb;
}

bool State::switchMode(AllModeType _type, bool flushUi) {
  if (only_read)
    return false;

  if (isModeType<DrawingModeType>(_type)) {
    return switchMode(getModeType<DrawingModeType>(_type), flushUi);
  } else if (isModeType<SelectModeType>(_type)) {
    return switchMode(getModeType<SelectModeType>(_type), flushUi);
  } else if (isModeType<EditingModeType>(_type)) {
    return switchMode(getModeType<EditingModeType>(_type), flushUi);
  }
  assert(0 && "预料之外的情况");
}

bool State::switchMode(DrawingModeType _type, bool flushUi) {
  if (only_read)
    return false;

  // 模式已存在或切换到空模式则退出
  if (_type == drawingMode && _type != DrawingModeType::None)
    return false;

  SPDLOG_INFO("Old-" + getModeInfo(*this));

  // if (drawingMode != DrawingModeType::None && _type == DrawingModeType::Fan) {
  //   bus.send(ExitModeEvent());
  // }

  // 进入绘制清空选中
  auto cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;

  auto view = reg.view<select::SelectTag>();
  view.each([&reg](entt::entity e) { reg.remove<select::SelectTag>(e); });

  auto& sele_event_writer = query.get_event_writer<select::Event>();
  sele_event_writer.send({select::Code::SelectUpdate});
  sele_event_writer.send({select::Code::HoverUpdate});

  // 记录进入前的选择模式
  if (selectMode != SelectModeType::None) {
    exitSelectMode = selectMode;
  }

  // 如果进入前绘制模式不为空，退出对应绘制模式
  if (drawingMode != DrawingModeType::None) {
    exitManager.exit(query, drawingMode, _type);
    drawingMode = DrawingModeType::None;
  }

  // 编辑模式同上
  if (editingMode != EditingModeType::None) {
    exitManager.exit(query, editingMode, EditingModeType::None);
    editingMode = EditingModeType::None;
  }

  // 切换到需要的模式
  drawingMode = _type;

  SPDLOG_INFO("New-" + getModeInfo(*this));

  // 刷新高亮
  if (flushUi) {
    FlushHeightLight event;
    event.drawing = drawingMode;
    event.editing = editingMode;
    event.select = selectMode;
    event.switchSelect = false;

    bus.send(event);
  }

  return true;
}

// 切换编辑模式
bool State::switchMode(EditingModeType _type, bool flushUi) {
  if (only_read)
    return false;

  // 如果模式已存在或切换到空则退出
  if (_type == editingMode && _type != EditingModeType::None)
    return false;

  SPDLOG_INFO("Old-" + getModeInfo(*this));

  // 记录进入前的选择模式
  if (selectMode != SelectModeType::None) {
    exitSelectMode = selectMode;
  }

  // 如果进入前编辑模式不为空，退出对应编辑模式
  if (_type != EditingModeType::None) {
    exitManager.exit(query, editingMode, _type);
  }

  // 绘制模式同上
  if (drawingMode != DrawingModeType::None) {
    exitManager.exit(query, drawingMode, _type);
    drawingMode = DrawingModeType::None;
  }

  // 切换到对应模式
  editingMode = _type;

  SPDLOG_INFO("New-" + getModeInfo(*this));

  // 刷新高亮
  if (flushUi) {
    FlushHeightLight event;
    event.drawing = drawingMode;
    event.editing = editingMode;
    event.select = selectMode;
    event.switchSelect = false;

    bus.send(event);
  }

  return true;
}

// 切换选择模式
bool State::switchMode(SelectModeType _type, bool flushUi) {
  if (only_read)
    return false;

  // 如果相同或为空则退出
  if (_type == selectMode || _type == SelectModeType::None)
    return false;

  SPDLOG_INFO("Old-" + getModeInfo(*this));

  // 按照旧版本，退出绘制模式
  if (drawingMode != state::DrawingModeType::None) {
    exitManager.exit(query, drawingMode, state::DrawingModeType::None);
    drawingMode = state::DrawingModeType::None;

    FlushHeightLight event;
    event.drawing = drawingMode;
    event.editing = editingMode;
    event.select = selectMode;

    bus.send(event);
  }

  // 如果在快速对齐，也退出
  if (editingMode == EditingModeType::QuickAlign) {
    exitManager.exit(query, editingMode, EditingModeType::None);
    editingMode = EditingModeType::None;

    if (!flushUi) {
      FlushHeightLight event;
      event.drawing = drawingMode;
      event.editing = editingMode;
      event.select = selectMode;
      event.switchSelect = false;

      bus.send(event);
    }
  }

  // 退出之前的模式
  exitManager.exit(query, selectMode, _type);

  // 切换到新模式
  selectMode = _type;

  SPDLOG_INFO("New-" + getModeInfo(*this));

  // 刷新高亮
  if (flushUi) {
    FlushHeightLight event;
    event.drawing = drawingMode;
    event.editing = editingMode;
    event.select = selectMode;
    event.switchSelect = true;

    bus.send(event);
  }

  return true;
}

// 回退模式
bool State::exit(bool flushUi) {
  if (only_read)
    return false;

  FlushHeightLight event;

  // 如果绘制模式不为空
  if (drawingMode != DrawingModeType::None) {
    SPDLOG_INFO("Old-" + getModeInfo(*this));

    // 退出绘制
    exitManager.exit(query, drawingMode, DrawingModeType::None);
    drawingMode = DrawingModeType::None;

    // 切换之前的选择模式
    // event.switchSelect = (selectMode == exitSelectMode);
    // selectMode = exitSelectMode;

    SPDLOG_INFO("New-" + getModeInfo(*this));

    // 刷新UI
    if (flushUi) {
      FlushHeightLight event;
      event.drawing = drawingMode;
      event.editing = editingMode;
      event.select = selectMode;

      bus.send(event);

      return true;
    }
  }

  // 如果编辑模式不为空
  if (editingMode != EditingModeType::None) {
    // SPDLOG_INFO("Old-" + getModeInfo(*this));

    // 退出编辑模式
    exitManager.exit(query, editingMode, EditingModeType::None);
    editingMode = EditingModeType::None;

    // 切换之前的选择模式
    // event.switchSelect = (selectMode == exitSelectMode);
    // selectMode = exitSelectMode;

    // 刷新UI
    if (flushUi) {
      FlushHeightLight event;
      event.drawing = drawingMode;
      event.editing = editingMode;
      event.select = selectMode;

      bus.send(event);

      return true;
    }

    SPDLOG_INFO("New-" + getModeInfo(*this));
    return true;
  }

  return false;
}

// 吸附
bool State::isAdsorption() {
  return adsorption;
}
void State::setAdsorption(bool value, bool flushUi) {
  adsorption = value;

  if (flushUi) {
    FlushHeightLightT event;
    event.isAdsorption = adsorption;
    bus.send(event);
  }
}

// 斜角吸附
bool State::isAngleTheAdsorption() {
  return angleTheAdsorption;
}
void State::setAngleTheAdsorption(bool value) {
  angleTheAdsorption = value;
}

// 角度锁定
bool State::isAngleLocking() {
  return angleLocking;
}
void State::setAngleLocking(bool value) {
  angleLocking = value;
}

double State::getAbsorbPrecision() {
  return precision;
}

void State::setAbsorbPrecision(double value) {
  precision = value;
}

bool State::getCurrentLayer(uint32_t& layer) {
  if (have_layer) {
    layer = curren_layer;
  }
  return have_layer;
}

// 内部使用
void State::setCurrentLayer(bool haveLayer) {
  have_layer = haveLayer;
}
void State::setCurrentLayer(uint32_t layer) {
  have_layer = true;
  curren_layer = layer;
}

bool State::switchMode(EditingChildMode mode) {
  if (only_read)
    return false;

  editingChildMode = mode;
  return true;
}
EditingChildMode State::getEditingChildMode() const {
  return editingChildMode;
}

bool State::switchMode(AutoRouteFixedDistanceStretchLineChildMode mode) {
  if (only_read)
    return false;

  autoRouteFixedDisStretchChildMode = mode;
  return true;
}
AutoRouteFixedDistanceStretchLineChildMode State::getAutoRouteFixedDistanceStretchLineChildMode() const {
  return autoRouteFixedDisStretchChildMode;
}
void State::reset(bool flushUi) {
  FlushHeightLight event;
  //event.switchSelect = (selectMode == state::SelectModeType::Overall);

  switchMode(state::DrawingModeType::None);
  switchMode(state::EditingModeType::None);
  switchMode(state::EditingChildMode::None);
  //switchMode(state::SelectModeType::Overall);

  if (flushUi) {
    event.drawing = drawingMode;
    event.editing = editingMode;
    //event.select = selectMode;

    bus.send(event);
  }
}

void State::onlyRead(bool value) {
  only_read = value;

  if (only_read) {

    drawingMode = DrawingModeType::None;
    editingMode = EditingModeType::None;
    selectMode = SelectModeType::None;
    editingChildMode = EditingChildMode::None;
  }
}

}  // namespace qbe::state
